﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.Collections;
using System.Net;
using System.Net.NetworkInformation;

using NetMonitor.Server;

namespace NetMonitor.ClassLib
{
    public partial class MyPoint : PictureBox
    {

        #region 构造器


        public MyPoint()
        {
            InitializeComponent();
            MyInit();

            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            UpdateStyles();            
        }
        

        /// <summary>
        /// 初始化的同时,给节点的序号赋值,每个节点有个index的序号
        /// </summary>
        /// <param name="index"></param>
        //public MyPoint(int index)
        //{
        //    this.index = index;
        //    MyInit();
        //}


        #endregion


        #region 变量 属性


        /*
        private int index = 0;
        /// <summary>
        /// 节点的序号,每次增加节点加1
        /// </summary>
        public int Index
        {
            get { return index; }
            set { index = value; }
        }
        */

        private string id;
        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        private int imgGroup = 0;
        public int ImgGroup
        {
            get { return imgGroup; }
            set { imgGroup = value; }
        }

        private string pointName;
        /// <summary>
        /// 节点的名称
        /// </summary>
        public string PointName
        {
            get { return pointName; }
            set { pointName = value; }
        }


        private string pointLocation;
        /// <summary>
        /// 节点的地理位置
        /// </summary>
        public string PointLocation
        {
            get { return pointLocation; }
            set { pointLocation = value; }
        }


        private IPAddress pointIpaddress;
        /// <summary>
        /// 节点的IP地址
        /// </summary>
        public IPAddress PointIpaddress
        {
            get { return pointIpaddress; }
            set { pointIpaddress = value; }
        }


        private Ping pingClient;


        // private bool isDisconnected = false;
        /// <summary>
        /// 表示是否联通
        /// </summary>
        public bool IsDisconnected
        {
            get { return connectivity == CONNECTIVITY_ALARM; }            
            // get { return isDisconnected; }
            set 
            {
                if (value)
                    connectivity = CONNECTIVITY_ALARM;
                else
                    connectivity = CONNECTIVITY_NORMAL;
            }
            // set { isDisconnected = value; }
        }
        

        /// <summary>
        /// 两个提示声
        /// </summary>
        SoundPlayer soundCon, soundDiscon,soundWarn;


        private Point pointPosition;
        /// <summary>
        /// 节点的X,Y坐标点,划线的时候当作坐标
        /// </summary>
        public Point PointPosition
        {
            get { return pointPosition; }
            set { pointPosition = value; }
        }


        private Image normalImage;
        /// <summary>
        /// 设置节点为正常图标
        /// </summary>
        public Image NormalImage
        {
            get { return normalImage; }
            set { normalImage = value; }
        }


        //private Bitmap selectImage;
        ///// <summary>
        ///// 设置节点为鼠标点击时的图标
        ///// </summary>
        //public Bitmap SelectImage
        //{
        //    get { return selectImage; }
        //}

        private Image disConnImage;
        /// <summary>
        /// 设置节点为报警时的图标
        /// </summary>
        public Image DisConnImage
        {
            get { return disConnImage; }
            set { disConnImage = value; }
        }

        private Image warnImage;
        /// <summary>
        /// 设置节点警示时代图标
        /// </summary>
        public Image WarnImage
        {
            get { return warnImage; }
            set { warnImage = value; }
        }

        
        public List<MyPoint> myDrawLinePoll;
        /// <summary>
        /// 定义一个集合,把所有和该点划线的MyPoint实例都储存进去
        /// </summary>
        public List<MyPoint> MyDrawLinePoll
        {
            get { return myDrawLinePoll; }
            set { myDrawLinePoll = value; }
        }

        private Timer pointTimer;

        private int pointType = 0;

        /// <summary>
        /// 节点的类型,1为大节点(主干、骨干)，2为小节点(地区、接入)
        /// </summary>
        public int PointType
        {
            get { return pointType; }
            set { pointType = value; }
        }


        // lryh ping忙标志(有一个Ping未返回)
        private bool isBusy = false;
        // lryh 丢包率
        private double dropRate = 0;
        // lryh 连通状态标志
        private string connectivity = CONNECTIVITY_ALARM;
        // lryh 短期历史记录
        private Queue<bool> queuePingLog = new Queue<bool>();
        // lryh 记录保存数量
        private const int QUEUE_PING_LOG_SIZE = 10;

        public string Connectivity
        {
            get 
            {
                if (connectivity == CONNECTIVITY_NORMAL)
                    return "联通";
                else if (connectivity == CONNECTIVITY_ALARM)
                    return "阻断";
                else
                    return "告警";
            }
        }

        // lryh 状态变换丢包率阈值
        //private const double DROP_RATE_ENTER_WARNING = 0.5;
        //private const double DROP_RATE_ENTER_ALARM = 0.8;
        //private const double DROP_RATE_QUIT_WARNING = 0.2;
        //private const double DROP_RATE_QUIT_ALARM = 0.5;

        private const double DROP_RATE_WARNING = 0.35;
        private const double DROP_RATE_ALARM = 0.8;


        // lryh 连通状态
        private const string CONNECTIVITY_NORMAL = "normal";
        private const string CONNECTIVITY_WARNING = "warning";
        private const string CONNECTIVITY_ALARM = "alarm";

        //will轮询时间设置
        private const int NORMAL_TIMER = 10000;
        private const int WARNING_TIMER = 3000;
        private const int ALERT_TIMER = 5000;


        #endregion


        #region 保留的属性

        private string soundURL;

        public string SoundURL
        {
            get { return soundURL; }
            set { soundURL = value; }
        }

        #endregion


        #region 方法


        /// <summary>
        /// 初始化,考虑到性能原因,不处理鼠标点击节点变色的事件(已经注释掉)
        /// </summary>
        private void MyInit()
        {
            myDrawLinePoll = new List<MyPoint>();
            
            pointTimer = new Timer();            
            SetPointTimer(ALERT_TIMER);

            //this.MouseUp += new MouseEventHandler(MyPoint_MouseUp);
            //this.MouseDown += new MouseEventHandler(MyPoint_MouseDown);
            pingClient = new Ping();
            pingClient.PingCompleted += new PingCompletedEventHandler(pingClient_PingCompleted);
            try
            {
                soundCon = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + @"sounds\connect.wav");
                soundDiscon = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + @"sounds\discon.wav");
                soundWarn = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + @"sounds\warn.wav");
            }
            catch (Exception ex)
            {
                MessageBox.Show("警告...", "加载声音文件错误 :" + ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        /// <summary>
        /// 计时器到期触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pointTimer_Tick(object sender, EventArgs e)
        {
            StartPing();
        }



        /// <summary>
        /// 设置节点的报警间隔时间,设置的时间应该至少大于1S
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        private bool SetPointTimer(int time)
        {
            if (pointTimer != null && time >= 1000)
            {
                pointTimer.Interval = time;
                return true;
            }
            return false;
        }


        /// <summary>
        /// 从外部开启计时器
        /// </summary>
        public void StartTimer()
        {
            pointTimer.Tick += new EventHandler(pointTimer_Tick);
            pointTimer.Start();
        }

        /// <summary>
        /// 从外部停止计时器
        /// </summary>
        public void StopTimer()
        {
            pointTimer.Stop();
        }


        /// <summary>
        /// 检测本point的划线poll中是否有参数mp
        /// </summary>
        /// <param name="mp"></param>
        /// <returns>如果有返回true,没有返回false</returns>
        public bool CheckIfhasMyPoint(MyPoint mp)
        {
            if (myDrawLinePoll.Count > 0)
            {
                if(MyDrawLinePoll.Contains(mp))
                {
                    return true;
                }
            }
            return false;
        }



        /// <summary>
        /// 在划线的poll里删除指定的MyPoint实例
        /// </summary>
        /// <param name="mp"></param>
        /// <returns></returns>
        public bool RemovePointFromPool(MyPoint mp)
        {
            if (myDrawLinePoll.Count > 0)
            {
                if (myDrawLinePoll.Contains(mp))
                {
                    myDrawLinePoll.Remove(mp);
                    return true;
                }
            }
            return false;
        }


        #region 有关测试网络联通的方法


        /// <summary>
        /// 开始ping
        /// </summary>
        private void StartPing()
        {
            if (pointIpaddress != null && !isBusy)
            {
                pingClient.SendAsync(pointIpaddress, null);
                isBusy = true;
            }
        }


        /// <summary>
        /// 停止ping
        /// </summary>
        private void StopPing()
        {
            pingClient.SendAsyncCancel();
        }



        /// <summary>
        /// lryh 添加记录，更新丢包率
        /// </summary>
        /// <param name="value">true代表丢包,false代表不代表</param>
        private void addPingEntry(bool value)
        {
            if (queuePingLog.Count == QUEUE_PING_LOG_SIZE)
            {
                queuePingLog.Dequeue();
                queuePingLog.Enqueue(value);
            }
            else
                queuePingLog.Enqueue(value);

            // lryh 计算丢包率
            bool[] dropLog = queuePingLog.ToArray();
            int drops = 0;
            for (int i = 0; i < dropLog.Length; i++)
            {
                if (dropLog[i])
                    drops++;
            }
            dropRate = (double)drops / (double)dropLog.Length;

            //// lryh 转换状态
            //if (connectivity == CONNECTIVITY_NORMAL)
            //{
            //    if (dropRate > DROP_RATE_ENTER_WARNING)
            //    {
            //        changeState(CONNECTIVITY_WARNING);
            //    }
            //}
            //else if (connectivity == CONNECTIVITY_WARNING)
            //{
            //    if (dropRate >= DROP_RATE_ENTER_ALARM)
            //        changeState(CONNECTIVITY_ALARM);
            //    else if (dropRate <= DROP_RATE_QUIT_WARNING)
            //        changeState(CONNECTIVITY_NORMAL);
            //}
            //else if (connectivity == CONNECTIVITY_ALARM)
            //{
            //    if (dropRate <= DROP_RATE_QUIT_ALARM)
            //        changeState(CONNECTIVITY_WARNING);
            //}

            if (connectivity == CONNECTIVITY_NORMAL)
            {
                if (dropRate > DROP_RATE_WARNING)
                {
                    changeState(CONNECTIVITY_WARNING);
                }
            }
            else if (connectivity == CONNECTIVITY_WARNING)
            {
                if (dropRate >= DROP_RATE_ALARM)
                    changeState(CONNECTIVITY_ALARM);
                else if (dropRate <= DROP_RATE_WARNING)
                    changeState(CONNECTIVITY_NORMAL);
            }
            else if (connectivity == CONNECTIVITY_ALARM)
            {
                if (dropRate <= DROP_RATE_ALARM)
                    changeState(CONNECTIVITY_WARNING);
            }

            Console.Out.WriteLine(pointName + "(" + pointIpaddress.ToString() + ") : " + connectivity + " (" + dropRate + ") -- Timer:" + pointTimer.Interval.ToString());
        }



        /// <summary>
        /// 设置当期状态
        /// </summary>
        /// <param name="value"></param>
        private void changeState(string value)
        {
            connectivity = value;

            if (value.Equals(CONNECTIVITY_NORMAL))
            {
                stateNormal();
                SetPointTimer(NORMAL_TIMER);
            }
            else if (value.Equals(CONNECTIVITY_WARNING))
            {
                stateWarning();
                SetPointTimer(WARNING_TIMER);
            }
            else if (value.Equals(CONNECTIVITY_ALARM))
            {
                stateAlart();
                SetPointTimer(ALERT_TIMER);
            }
        }

        /// <summary>
        /// ICMP检测代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pingClient_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            //检测未出错情况下
            if (e.Error == null)
            {

                if (e.Cancelled)
                {
                    //如果点击"取消"相应语句
                    MessageBox.Show("用户取消了连通性测试");
                    return;
                }
                else
                {
                    if (e.Reply.Status == IPStatus.Success)
                    {
                        //PING返回成功
                        addPingEntry(false); ;
                    }
                    else
                    {
                        //PING返回失败
                        addPingEntry(true);
                    }
                }
            }
            else
            {
                // 检测出错的情况下           
                MessageBox.Show("An error occurred while sending this ping. " + e.Error.InnerException.Message);
                stateAlart();
            }
            // lryh 一个ping完成后清空忙标志
            isBusy = false;
        }



        #endregion


        #region 鼠标点击外观变色,当前已注释掉

        //void MyPoint_MouseDown(object sender, MouseEventArgs e)
        //{
        //    SetSelectImage();
        //}


        //void MyPoint_MouseUp(object sender, MouseEventArgs e)
        //{
        //    if (isDisconnected)
        //    {
        //        SetDisconImage();
        //    }
        //    else
        //    {
        //        SetNormalImage();
        //    }
        //}

        #endregion


        #region 报警检测

        /// <summary>
        /// 警告
        /// </summary>
        private void stateWarning()
        {
            soundWarn.Play();
            SetWarnImage();
        }

        /// <summary>
        /// 阻断
        /// </summary>
        private void stateAlart()
        {
            soundDiscon.Play();
            SetDisconImage();
        }


        /// <summary>
        /// 联通
        /// </summary>
        private void stateNormal()
        {
            soundCon.Play();
            SetNormalImage();
        }

        #endregion


        #region 设置图片

        /// <summary>
        /// 将图标设置为默认图标
        /// </summary>
        private void SetNormalImage()
        {
            if (normalImage != null)
            {
                this.Image = normalImage;
            }
        }

        /// <summary>
        /// 将图标设置为选择图标,当前该状态已经被注释
        /// </summary>
        //public void SetSelectImage()
        //{
        //    if (selectImage != null)
        //    {
        //        this.Image = selectImage;
        //    }
        //}


        /// <summary>
        /// 将图标设置为阻断图标
        /// </summary>
        public void SetDisconImage()
        {
            if (disConnImage != null)
            {
                this.Image = disConnImage;

                if (imgGroup == 9)
                {
                    this.Image = Image.FromFile(Application.StartupPath + "/images/discon_bling.gif");
                }
            }
        }


        /// <summary>
        ///  将图标设置为警示图标
        /// </summary>
        public void SetWarnImage()
        {
            if (warnImage != null)
            {
                this.Image = warnImage;
            }
        }


        #endregion

        #endregion


        public void startCheckServer()
        {
            pointTimer.Tick += new EventHandler(this.check);
            pointTimer.Start();
        }

        private void check(object sender, EventArgs e)
        {
            string state = NetMonClient.GetClient("").checkConnectivity(pointName);
            if (!state.Equals(connectivity))
                changeState(state);
        }

        public void RefreshImage()
        {
            if (connectivity.Equals(CONNECTIVITY_NORMAL))
                SetNormalImage();
            else if (connectivity.Equals(CONNECTIVITY_WARNING))
                SetWarnImage();
            else if (connectivity.Equals(CONNECTIVITY_ALARM))
                SetDisconImage();
        }

    }
}
